import sys
import os
import re
import time
import traceback
# pyqt5类库
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QMessageBox
from PyQt5.QtCore import QThread, pyqtSignal

from Ui_main import Ui_MainWindow
# 读取excel
import xlrd
# 读取word
# import docx
# word 模板
from docxtpl import DocxTemplate, InlineImage, RichText
# 系统com组件
import comtypes.client
# from win32com import client

# 合并pdf
from PyPDF2 import PdfFileMerger

# 配置文件
import configparser


# 自定义异常


class ConvertException(Exception):
    pass


# 自定义QT线程类
class WorkThread(QThread):
    showInfoTrigger = pyqtSignal(str)
    showMessageBoxTrigger = pyqtSignal(dict)
    buttonEnabledControl = pyqtSignal(bool)
    winObj = {}

    def __int__(self):
        # 初始化函数
        super(WorkThread, self).__init__()

    def run(self):
        start_time = time.time()
        try:
            self.winObj.convert()
        except ConvertException as errorMsg:
            self.showMessageBoxTrigger.emit(errorMsg.args[0])
        except BaseException:
            traceback.print_exc()
            self.showMessageBoxTrigger.emit({
                'title': '失败',
                'content': '转换失败，请重试！'})
        else:
            # QMessageBox.information(
            #     self, "完成", "转换完成", QMessageBox.Ok)
            self.buttonEnabledControl.emit(True)
            self.showMessageBoxTrigger.emit({
                'title': '完成',
                'content': '转换完成！，用时（s）' + str((time.time()-start_time))
            })
        finally:
            self.buttonEnabledControl.emit(True)


class MyWindow (QMainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.work = WorkThread()
        self.work.showInfoTrigger.connect(self.showInfoToGui)
        self.work.showMessageBoxTrigger.connect(self.showMessageBoxToGui)
        self.work.buttonEnabledControl.connect(self.setStartButtonEnabled)

        config = configparser.ConfigParser()
        # 配置管理
        self.config = config
        self.BaseSectionName = 'Base'
        # 读取配置文件
        currentWorkFolder = os.path.abspath('.')
        print(currentWorkFolder)
        self.configFilePath = os.path.join(currentWorkFolder, 'config.ini')

        # 如果文件已经存在
        if os.path.exists(self.configFilePath):
            config.read(self.configFilePath)
        else:
            config.add_section(self.BaseSectionName)
            with open('config.ini', 'w+') as configFile:
                config.write(configFile)
                config.read(configFile)
                pass

    # 读取配置

    def initEditTextValueFromConfig(self, config):

        if not config.has_section(self.BaseSectionName):
            config.add_section(self.BaseSectionName)

        try:
            self.excelFilePath = config.get(
                self.BaseSectionName, 'excelFilePath')
            self.UIObj.excelPathEdit.setText(self.excelFilePath)

            self.wordFilePath = config.get(
                self.BaseSectionName, 'wordFilePath')
            self.UIObj.wordPathEdit.setText(self.wordFilePath)

            self.imgDirPath = config.get(self.BaseSectionName, 'imgDirPath')
            self.UIObj.imgPathEdit.setText(self.imgDirPath)

            self.pdfDirPath = config.get(self.BaseSectionName, 'pdfDirPath')
            self.UIObj.pdfPathEdit.setText(self.pdfDirPath)

        except BaseException as ex:
            traceback.print_exc()
            pass
        else:
            pass

    # 配置文件
    def setConfig(self, key, value):
        self.config.set(self.BaseSectionName, key, value)
        pass

    def chooseFile(self):
        # 事件发送者
        sender = self.sender()
        chooseType = sender.property('chooseType')
        # 文件类型
        fileType = ""
        if chooseType == 'excel':
            print('要选择excel')
            fileType = "Excel Files(*.xlsx *.xls);"
        elif chooseType == 'word':
            print('要选择word')
            fileType = "Excel Files(*.docx);"
        fileName, fileType = QtWidgets.QFileDialog.getOpenFileName(
            self, "选取文件", os.getcwd(), fileType)
        if fileName != '':
            if chooseType == 'excel':
                self.UIObj.excelPathEdit.setText(fileName)
            elif chooseType == 'word':
                self.UIObj.wordPathEdit.setText(fileName)

    def chooseFolder(self):
        # 事件发送者
        sender = self.sender()
        chooseType = sender.property('chooseType')

        dirPath = QtWidgets.QFileDialog.getExistingDirectory(self)

        if chooseType == 'img':
            self.UIObj.imgPathEdit.setText(dirPath)
        elif chooseType == 'pdf':
            self.UIObj.pdfPathEdit.setText(dirPath)

    def setUIObj(self, UIObj):
        self.UIObj = UIObj
        self.initEditTextValueFromConfig(self.config)

    def showInfoToGui(self, text):
        self.UIObj.infoLabel.setText(text)

    def showMessageBoxToGui(self, messageObj):
        QMessageBox.warning(
            self, messageObj['title'], messageObj['content'], QMessageBox.Ok)

    def setStartButtonEnabled(self, enabled=True):
        self.UIObj.startButton.setEnabled(enabled)

    def startConvert(self):
        # 初始化
        self.UIObj.startButton.setEnabled(False)

        self.excelFilePath = self.UIObj.excelPathEdit.text()
        self.wordFilePath = self.UIObj.wordPathEdit.text()
        self.imgDirPath = self.UIObj.imgPathEdit.text()
        self.pdfDirPath = self.UIObj.pdfPathEdit.text()

        # 保存配置
        self.setConfig('excelFilePath', self.excelFilePath)
        self.setConfig('wordFilePath', self.wordFilePath)
        self.setConfig('imgDirPath', self.imgDirPath)
        self.setConfig('pdfDirPath', self.pdfDirPath)
        with open(self.configFilePath, 'w+') as configFile:
            self.config.write(configFile)
            pass
        # 开始
        self.work.winObj = self
        self.work.start()

    def convert(self):
        excelFilePath = self.excelFilePath
        wordFilePath = self.wordFilePath
        imgDirPath = self.imgDirPath
        pdfDirPath = self.pdfDirPath
        if len(excelFilePath) == 0:
            errorMsg = {
                'title': 'Excel未选择',
                'content': '请选择Excel文件！'
            }
            raise ConvertException(errorMsg)
        if len(wordFilePath) == 0:
            errorMsg = {
                'title': 'Word未选择',
                'content': '请选择Word文件！'
            }
            raise ConvertException(errorMsg)
        if len(pdfDirPath) == 0:
            errorMsg = {
                'title': 'Pdf目录未选择',
                'content': '请选择Pdf目录！'
            }
            raise ConvertException(errorMsg)
        """ if len(imgDirPath) == 0:
            self.work.showMessageBoxTrigger.emit({
                'title': '图片路径未选择',
                'content': '图片路径未选择，将不会处理图片字段！'
            }) """
        # return
        existPdfFileList = []
        # 获取pdf目录下的pdf文件
        for pdfPathFileName in os.listdir(pdfDirPath):
            if pdfPathFileName.endswith('.pdf'):
                existPdfFileList.append(
                    os.path.join(pdfDirPath, pdfPathFileName))

        # 得到word所在的Folder
        wordFileFolder = wordFilePath[0: wordFilePath.rindex(str('/'))]

        # 读取excel
        excelWordBook = xlrd.open_workbook(excelFilePath)

        # 初始化com组件
        comtypes.CoInitialize()
        wordApplication = comtypes.client.CreateObject("Word.Application")

        # 读取word模板
        wordTemplate = DocxTemplate(wordFilePath)

        # 表格单元格大小字典（查找包含模板字符的单元格）
        tableSizeMap = {}

        # title名称
        titleRowArray = []

        # 子系统名称对应的文件夹 字典
        globalConfigDict = {}

        try:
            # 查找名字是'Config.'的 sheet
            configSheet = excelWordBook.sheet_by_name('Config.')

            # 形成 Sub System : MR Number + '-' + Short System Name 的字典对象

            # 查找三列对应的 列index
            configTitleRow = configSheet.row(0)
            systemColIndex = 0
            poNumberColIndex = 0
            joNumberColIndex = 0
            mRNumberColIndex = 0
            systemNameColIndex = 0
            shortSystemIndex = 0
            projectNameColIndex = 0
            for configTitleIndex, configTitleCol in enumerate(configTitleRow):
                if configTitleCol.value.lstrip() == 'System':
                    systemColIndex = configTitleIndex
                elif configTitleCol.value.lstrip() == 'PO Number':
                    poNumberColIndex = configTitleIndex
                elif configTitleCol.value.lstrip() == 'JO Number':
                    joNumberColIndex = configTitleIndex
                elif configTitleCol.value.lstrip() == 'MR Number':
                    mRNumberColIndex = configTitleIndex
                elif configTitleCol.value.lstrip() == 'System Name':
                    systemNameColIndex = configTitleIndex
                elif configTitleCol.value.lstrip() == 'Short System Name':
                    shortSystemIndex = configTitleIndex
                elif configTitleCol.value.lstrip() == 'PROJECT NAME':
                    projectNameColIndex = configTitleIndex

            for configRowIndex in range(configSheet.nrows):
                if configRowIndex == 0:
                    continue
                systemColValue = configSheet.cell(
                    configRowIndex, systemColIndex).value
                poNumberColValue = configSheet.cell(
                    configRowIndex, poNumberColIndex).value
                joNumberColValue = configSheet.cell(
                    configRowIndex, joNumberColIndex).value
                mRNumberColValue = configSheet.cell(
                    configRowIndex, mRNumberColIndex).value
                systemNameColValue = configSheet.cell(
                    configRowIndex, systemNameColIndex).value
                shortSystemValue = configSheet.cell(
                    configRowIndex, shortSystemIndex).value
                projectNameColValue = configSheet.cell(
                    configRowIndex, projectNameColIndex).value
                # 完善globalConfigDict字典
                globalConfigDict[systemColValue] = {
                    'systemNumberDict': (str(mRNumberColValue) + '-' + shortSystemValue),
                    'pONumber': poNumberColValue,
                    'jONumber': joNumberColValue,
                    'mRNumber': mRNumberColValue,
                    'systemName': systemNameColValue,
                    'shortSystemName': shortSystemValue,
                    'projectName': projectNameColValue
                }

            # 遍历每一个sheet
            for sheetIndex, mainSheet in enumerate(excelWordBook.sheets()):
                # 查找sheet名字 不是 'Note' 和 'Config.'的sheet
                if mainSheet.name != 'Config.' and mainSheet.name != 'Note':
                    # 遍历行
                    for rIndex in range(mainSheet.nrows):
                        rowPassed = False
                        # 跳过第一行
                        if rIndex == 0:
                            continue
                        # 处理excel数据
                        rows = mainSheet.row(rIndex)
                        # 如果标题行为空
                        if len(titleRowArray) == 0:
                            # 第一行为title
                            titleRow = mainSheet.row(0)
                            if len(titleRow) == 0:
                                errorMsg = {
                                    'title': 'Excel异常',
                                    'content': 'Excel第一行不能为空！'
                                }
                                raise ConvertException(errorMsg)
                            for titleCol in titleRow:
                                titleRowArray.append(titleCol.value)
                            # 打印title
                            print(titleRowArray)
                        pass

                        print('正在处理sheet: %s 的第 %d 行' %
                              (mainSheet.name, rIndex))
                        self.work.showInfoTrigger.emit(
                            '正在处理sheet: %s 的第 %d 行,共 %d 行' % (mainSheet.name, rIndex, (mainSheet.nrows - 1)))

                        if len(tableSizeMap) == 0:
                            # 模板对象 转换成docx对象
                            docxFile = wordTemplate.get_docx()
                            # 开始遍历docx里面的表格
                            allTables = docxFile.tables
                            # 读取表格单元格大小
                            for table in allTables:
                                for index, row in enumerate(table.rows):
                                    # 行高
                                    height = 0
                                    height = row.height
                                    for cell in row.cells:
                                        # 判断是否有模板值
                                        searchObj = re.search(
                                            r'{{[a-zA-Z0-9]*}}', str(cell.text), re.M | re.I)
                                        # 如果有
                                        if searchObj:
                                            searchResult = str(
                                                searchObj.group())
                                            titleKey = searchResult[2:len(
                                                searchResult) - 2]
                                            # 列宽
                                            width = 0
                                            width = cell.width
                                            tableSizeMap[titleKey] = {
                                                'width': width,
                                                'height': height
                                            }
                                        pass
                                    pass
                                pass
                            pass
                        pass
                        ''' 初始化变量 '''
                        # 子系统名称
                        subSystem = ''
                        # 文件号
                        clientDocumentNo = ''
                        # 版本号
                        rev = ''
                        # 批次号
                        batchText = ''
                        # 初始化模板数据
                        templateData = {}
                        # 遍历列
                        for index, col in enumerate(rows):
                            # print(col.value, '---', end="")
                            content = str(col.value)
                            # 第一列不处理
                            if index == 0:
                                # 如果标记为不处理
                                if content.lstrip() == 'Yes' or content.lstrip() == 'YES' or content.lstrip() == 'yes':
                                    continue
                                else:
                                    rowPassed = True
                                    break

                            # titleKey
                            titleKey = str(titleRowArray[index])
                            # 处理title的内容 （空格转_）
                            # titleKey.replace(r' |\/|\|', '_')
                            titleKeyConvert = re.sub(
                                r" |\/|\\|\.", "_", titleKey)
                            # titleKeyConvert = titleKeyConvert.replace('.', '_')

                            if content.startswith('image:'):
                                if (not imgDirPath.isspace()) and len(imgDirPath) != 0:
                                    imagePath = os.path.join(
                                        imgDirPath, content[6:])
                                    widthAndHeight = {
                                        'width': None,
                                        'height': None
                                    }
                                    if titleKey in tableSizeMap.keys():
                                        # 高度和宽度
                                        widthAndHeight = tableSizeMap[titleKey]

                                    # print(widthAndHeight)
                                    templateData[titleKeyConvert] = InlineImage(
                                        wordTemplate, imagePath, widthAndHeight['width'], widthAndHeight['height'])

                            else:
                                templateData[titleKeyConvert] = content
                                # 取值
                                if titleKey == 'Sub System':
                                    subSystem = content
                                if titleKey == 'Client Document No.':
                                    clientDocumentNo = content
                                if titleKey == 'Rev.':
                                    rev = content
                                if batchText == '' and titleKey.find('Batch') != -1 and content.lstrip() != '':
                                    if col.ctype == 3:
                                        batchText = xlrd.xldate_as_datetime(
                                            col.value, 0).strftime('%Y-%m-%d')
                                    else:
                                        batchText = content
                        pass
                        # 判断是否跳过
                        if rowPassed:
                            continue
                        # 增加config参数
                        templateData['PO_Number'] = globalConfigDict[subSystem]['pONumber']
                        templateData['JO_Number'] = globalConfigDict[subSystem]['jONumber']
                        templateData['MR_Number'] = globalConfigDict[subSystem]['mRNumber']
                        templateData['System_Name'] = globalConfigDict[subSystem]['systemName']
                        templateData['Short_System_Name'] = globalConfigDict[subSystem]['shortSystemName']
                        templateData['PROJECT_NAME'] = globalConfigDict[subSystem]['projectName']
                        templateData['sheetName'] = mainSheet.name

                        print(templateData)

                        if batchText == '':
                            batchText = 'A'

                        print('开始渲染...')
                        # 处理模板
                        wordTemplate.render(templateData)
                        # 保存文件的路径
                        saveFileFolder = os.path.join(
                            wordFileFolder, 'Output', globalConfigDict[subSystem]['systemNumberDict'], clientDocumentNo)
                        nativeFolder = os.path.join(
                            saveFileFolder, 'Native', batchText)
                        saveFilePath = os.path.join(
                            nativeFolder, clientDocumentNo + rev + 'Cover.docx')
                        # 如果文件夹不存在则创建
                        if not os.path.exists(saveFileFolder):
                            os.makedirs(saveFileFolder)
                            os.makedirs(nativeFolder)
                        # 如果文件已经存在
                        if os.path.exists(saveFilePath):
                            os.remove(saveFilePath)
                        # 保存生成的word文件
                        wordTemplate.save(saveFilePath)

                        """ # word转pdf
                        try:
                            # tempWordFile = comtypes.client.CreateObject("Word.Application")
                            # tempWordFile = self.wordApplication
                            tempPdfFile = wordApplication.Documents.Open(
                                saveFilePath, ReadOnly=1)
                            pdfSavePath = os.path.join(
                                saveFileFolder, 'convertFile.pdf')
                            # 如果文件已经存在
                            if os.path.exists(pdfSavePath):
                                os.remove(pdfSavePath)
                            tempPdfFile.SaveAs(pdfSavePath, FileFormat=17)

                            # 合并pdf
                            pdfList = [pdfSavePath]
                            pdfList = pdfList + existPdfFileList

                            # 初始化PdfFileMerger对象
                            file_merger = PdfFileMerger(False)
                            for pdfIndex, pdfFile in enumerate(pdfList):
                                file_merger.append(pdfFile)
                            file_merger.write(os.path.join(
                                saveFileFolder, 'convertMergerFile.pdf'))
                        except:
                            tempPdfFile.Close()
                            wordApplication.Quit()
                        finally:
                            if mainSheet.nrows == (rIndex + 1):
                                tempPdfFile.Close()
                            file_merger.close()
                        pass """
                pass
            pass
            print('for 完毕！')
        except BaseException as ex:
            traceback.print_exc()
            pass
        finally:
            wordApplication.Quit()

        # print('转换完毕，请等待输出！')
        # self.work.showInfoTrigger.emit('转换完毕，请等待文件输出！')
        # print(len(pdfMergeArray))
        # 线程post消息
        self.work.showInfoTrigger.emit('请点击开始转换！')
        # 打开资源管理器
        os.startfile(wordFileFolder)


class MyUI (Ui_MainWindow):
    def __init__(self):
        super(MyUI, self).__init__()
        win = MyWindow()
        self.setupUi(win)
        self.win = win
        win.setUIObj(self)

    def show(self):
        self.win.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    myUI = MyUI()
    # ui = Ui_main.Ui_MainWindow()
    # ui.setupUi(MainWindow)
    # myWindow.show()
    myUI.show()
    sys.exit(app.exec_())
